package com.lagou.sqlSession;
/*
 * PackageName: com.lagou.sqlSession
 * ClassName:
 * Author:   zhang
 * Date:     Created in 2020/9/29
 * Description:
 * History:
 * <author>        <time>             <version>          <desc>
 * 作者姓名         修改时间            版本号              描述
 * zhang           2020/9/29      1.0
 */

import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;

import java.lang.reflect.*;
import java.util.List;

/**
 * Title:
 * Project: IPersistence_test
 *
 * @author ZhangKe
 * Created on 2020/9/29
 */
public class DefaultSqlSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... param) throws Exception {

        //将要完成SimpleExecutor的query方法调用
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get((Object)statementId);
        List<Object> result = simpleExecutor.query(configuration, mappedStatement, param);
        return (List<E>) result;
    }

    @Override
    public <T> T selectOne(String statementId, Object... param) throws Exception {
        List<Object> objects = selectList(statementId, param);
        if (objects.size()==1){
            return (T) objects.get(0);
        }else{
            throw new RuntimeException("查询结果为空，或返回结果过多");
        }
    }

    @Override
    public <E> E insert(String statementId, Object... param) throws Exception {
        //将要完成SimpleExecutor的query方法调用
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get((Object)statementId);
        Object result = simpleExecutor.update(configuration, mappedStatement, param);
        return (E) result;
    }

    @Override
    public <E> E delete(String statementId, Object... param) throws Exception {
        //将要完成SimpleExecutor的query方法调用
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get((Object)statementId);
        Object result = simpleExecutor.update(configuration, mappedStatement, param);
        return (E) result;
    }

    @Override
    public <E> E update(String statementId, Object... param) throws Exception {
        //将要完成SimpleExecutor的query方法调用
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get((Object)statementId);
        Object result = simpleExecutor.update(configuration, mappedStatement, param);
        return (E) result;
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        //使用JDK动态代理来为Dao接口生成代理对象，并返回
        Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //代理对象调用接口中任何方法，都会执行invoke方法
                //底层还是执行jdbc，根据不同情况，来调用selectList或者selectOne
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();

                String statementId = className + "." + methodName;

                //获取调用方法的返回值类型
                Type genericReturnType = method.getGenericReturnType();
                String sqlType = configuration.getMappedStatementMap().get(statementId).getSqlType();
                if (sqlType.equalsIgnoreCase("INSERT")){
                    return insert(statementId,args);
                }
                else if (sqlType.equalsIgnoreCase("DELETE")){
                    return delete(statementId,args);
                }
                else if (sqlType.equalsIgnoreCase("SELECT")){
                    //判断是否进行了泛型类型参数化(是：集合；  不是：实体类)
                    if (genericReturnType instanceof ParameterizedType) {
                        List<Object> objects = selectList(statementId, args);
                        return objects;
                    }else{
                        return selectOne(statementId, args);
                    }
                }
                else{
                    return update(statementId,args);
                }
            }
        });
        return (T) proxyInstance;
    }
}
